<template>
  <svg viewBox="0 0 100 100" class="progress-ring">
    <defs>
      <linearGradient
        v-if="props.colorType === 'linear' || props.colorType === 'conic'"
        :id="`${componentID}-linear-gradient1`"
        :x1="linearGradient1.x1" :y1="linearGradient1.y1"
        :x2="linearGradient1.x2" :y2="linearGradient1.y2"
      >
        <stop v-for="(item, index) in linearGradient1.colors" :key="index" :stop-color="item.color" :offset="item.offset" />
      </linearGradient>
      <linearGradient
        v-if="props.colorType === 'conic'"
        :id="`${componentID}-linear-gradient2`"
        x1="0" y1="1"
        x2="0" y2="0"
      >
        <stop v-for="(item, index) in linearGradient2" :key="index" :stop-color="item.color" :offset="item.offset" />
      </linearGradient>
      <mask :id="`${componentID}-bar-mask`">
        <path :d="allPathD" fill="none" stroke="#000" :stroke-width="props.strokeWidth" />
        <path
          :d="allPathD" fill="none" stroke="#FFF"
          :stroke-width="props.strokeWidth"
          :style="{ strokeDasharray: pathStrokeDasharray + ', 314', opacity: pathStrokeDasharray > 0 ? 1 : 0 }"
          style="transition: stroke-dasharray 0.6s ease 0s, stroke 0.6s ease 0s, opacity 0.6s ease 0s"
          stroke-linecap="round"
        />
      </mask>
      <mask :id="`${componentID}-bg-mask`">
        <path stroke="#000" :stroke-width="props.strokeWidth" :d="allPathD" />
        <path
          :d="allPathD" fill="none" stroke="#FFF"
          :stroke-width="props.strokeWidth"
          :style="{ strokeDasharray: maxStrokeDasharray + ', 314' }"
          style="transition: stroke-dasharray 0.6s ease 0s, stroke 0.6s ease 0s, opacity 0.6s ease 0s"
          stroke-linecap="round"
        />
      </mask>
    </defs>
    <path
      :mask="`url('#${componentID}-bg-mask')`" :d="allPathD" fill="none"
      :stroke="props.bgColor"
      :stroke-width="props.strokeWidth"
    />
    <g :mask="`url('#${componentID}-bar-mask')`">
      <!--后半线-->
      <path
        v-if="props.colorType === 'conic'" :d="path2D" fill="none"
        :stroke="`url('#${componentID}-linear-gradient2')`"
        :stroke-width="props.strokeWidth"
      />
      <!--前半线-->
      <path
        :d="path1D" fill="none" :stroke="props.colorType === 'pure' ? props.color : `url('#${componentID}-linear-gradient1')`"
        :stroke-width="props.strokeWidth" stroke-linecap="round"
      />
    </g>
  </svg>
</template>

<script lang="ts" setup>
import { withDefaults } from 'vue'
import { ConicColorType, GradientColor, LinearColorType } from './type'
import { getComponentID } from './util'
import { ObjectUtil } from '@utils/object-util'

const props = withDefaults(defineProps<{
  // 当前进度
  percentage: number,
  // 线宽
  strokeWidth?: number,
  // 背景颜色
  bgColor?: string,
  // 颜色类型 纯色,线性渐变,锥形渐变
  colorType?: 'pure' | 'linear' | 'conic'
  // 纯色颜色
  color?: string,
  // 线性渐变颜色
  linearColor?: LinearColorType
  // 锥形渐变颜色
  conicColor?: ConicColorType,
  // 逆时针
  anticlockwise?: boolean,
  // 最大角度
  maxAngle?: number
}>(), {
  strokeLinecap: 'round',
  strokeWidth: 6,
  colorType: 'pure',
  anticlockwise: false,
  color: 'var(--el-color-primary)',
  maxAngle: 360,
  bgColor: '#ebeef5'
})

const componentID = ref(getComponentID())

onMounted(() => {
  init()
})

function init () {
  initPathD()
  initColor()
  nextTick(updatePercentage)
}

// region TODO 画线
// 圆半径
let circleRadius = 0
// 全路径
const allPathD = ref('')
// path1 路径
const path1D = ref('')
// path2 路径
const path2D = ref('')
// strokeDasharray 最大值
const maxStrokeDasharray = ref(314)
// 初始化pathD
function initPathD () {
  circleRadius = 50 - props.strokeWidth / 2
  maxStrokeDasharray.value = circleRadius * 314 * (props.maxAngle / 360) / 50
  const clockwise = props.anticlockwise ? 0 : 1
  // 前半段路径
  const pathSD = `a ${circleRadius} ${circleRadius} 0 1 ${clockwise} 0 ${100 - props.strokeWidth}`
  // 后半段路径
  const pathED = `a ${circleRadius} ${circleRadius} 0 1 ${clockwise} 0 -${100 - props.strokeWidth}`

  allPathD.value = `M 50 50 m 0 -${circleRadius} ${pathSD} ${pathED}`
  if (props.colorType === 'conic') {
    path1D.value = `M 50 50 m 0 -${circleRadius} ${pathSD}`
    path2D.value = `M 50 50 m 0 ${circleRadius} ${pathED}`
  } else {
    path1D.value = allPathD.value
  }
}
watch(() => props.strokeWidth, initPathD)
// endregion

// region TODO 进度
const pathStrokeDasharray = ref(0)
watch(() => props.percentage, updatePercentage)
function updatePercentage () {
  pathStrokeDasharray.value = circleRadius * 3.14 * (props.percentage) * (props.maxAngle / 360) / 50
}
// endregion

// region TODO 颜色
const linearGradient1 = ref<LinearColorType>({ x1: 0, y1: 0, x2: 0, y2: 1, colors: [] })

const linearGradient2 = ref<GradientColor[]>([])

function initColor () {
  switch (props.colorType) {
    case 'linear':
      linearGradient1.value = { x1: 0, y1: 0.5, x2: 1, y2: 0.5, colors: [], ...props.linearColor }
      break
    case 'conic':
      linearGradient1.value = {
        x1: 0, y1: 0, x2: 0, y2: 1, colors: props.conicColor.color1
      }
      const _linearGradient2 = []
      const endColor = ObjectUtil.copy(props.conicColor.color1[props.conicColor.color1.length - 1])
      endColor.offset = '0%'
      endColor && _linearGradient2.push(endColor)
      linearGradient2.value = _linearGradient2.concat(props.conicColor.color2)
      break
  }
}
// endregion

</script>

<style lang="scss" scoped>
.progress-ring {
  width: 100px;
  height: 100px;
  overflow: hidden;
}
</style>
